/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2012. All Rights Reserved.                        */
/* Open Source Software - may be modified and shared by FRC teams. The code   */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project.                                                               */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;

import org.usfirst.frc2084.robotsimulator.hardware.DigitalIO;
import org.usfirst.frc2084.robotsimulator.hardware.crio.cRIO;
import edu.wpi.first.wpilibj.communication.ModulePresence;

/**
 * Class representing a digital module
 */
public class DigitalModule extends Module {

    private static final int PWM_OUTPUTS = 10; // number of PWN outputs on the sidecar
    private static final int DIGITAL_IO_PORTS = 14; // number of digital I/O ports
    private static final int RELAY_OUTPUTS = 8;  // number of relay outputs
    private static final int I2C_PORTS = 4;  // number of I2C ports
    private final PWM[] pwmOutputs = new PWM[PWM_OUTPUTS];
    private final DigitalIO[] dIO = new DigitalIO[DIGITAL_IO_PORTS];
    private final Relay[] relayOutputs = new Relay[RELAY_OUTPUTS];
    private final I2C[] i2cComponents = new I2C[I2C_PORTS];

    public DigitalModule(int slot) {
        super(ModulePresence.ModuleType.kDigital, slot);
        cRIO.getInstance().add(this);
    }

    public void add(PWM c) {
        if (pwmOutputs[c.getChannel()] == null && c.getChannel() <= PWM_OUTPUTS) {
            pwmOutputs[c.getChannel()] = c;
        } else {
            throw new IllegalArgumentException("PWM output " + c.getChannel() + " is already taken!");
        }
    }

    public void add(DigitalIO c) {
        int channel = c.getChannel();
        if (dIO[channel] == null && c.getChannel() <= DIGITAL_IO_PORTS) {
            dIO[channel] = c;
        } else {
            throw new IllegalArgumentException("Digital I/O " + channel + " is already taken!");
        }
    }

    public void add(Relay c) {
        int channel = c.getChannel();
        if (relayOutputs[channel] == null && c.getChannel() <= RELAY_OUTPUTS) {
            relayOutputs[channel] = c;
        } else {
            throw new IllegalArgumentException("Relay output " + channel + " is already taken!");
        }
    }

    /**
     * Return an I2C object for this digital module
     *
     * @param address The device address.
     * @return The associated I2C object.
     */
    public I2C getI2C(final int address) {
        if (i2cComponents[address] == null && address <= I2C_PORTS) {
            I2C i = new I2C(this, address);
            i2cComponents[address] = i;
            return i;
        } else {
            throw new IllegalArgumentException("I2C address " + address + " is already taken!");
        }

    }

    @Override
    public int getModuleNumber() {
        return m_moduleNumber;
    }

    // Need a better way to interface with (virtual) hardware.
    
    void setRelayForward(int channel, boolean doIt) {
        if (doIt) {
            relayOutputs[channel-1].setDirection(Relay.Direction.kForward);
        }
    }

    void setRelayReverse(int channel, boolean doIt) {
        if (doIt) {
            relayOutputs[channel-1].setDirection(Relay.Direction.kReverse);
        }
    }

    boolean getRelayForward(int channel) {
        return relayOutputs[channel-1].get().equals(Relay.Value.kForward);
    }

    boolean getRelayReverse(int channel) {
        return relayOutputs[channel-1].get().equals(Relay.Value.kReverse);
    }

    void setPWM(int m_channel, int kPwmDisabled) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

    int getPWM(int m_channel) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

    void setPWMPeriodScale(int m_channel, int i) {
        throw new UnsupportedOperationException("Not yet implemented");
    }
}
